<template>
  <div ref="coder" class="corder">
    <select v-model="localLanguage">
      <option
        v-for="item in Object.keys(langConfigMap)"
        :key="item"
        :value="item"
      >
        {{ item }}
      </option>
    </select>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { useThrottleFn } from '@vueuse/core';

import { oneDark } from '@codemirror/theme-one-dark';
// import { EditorState, Compartment } from '@codemirror/state';
import { keymap } from '@codemirror/view';
import { basicSetup, EditorView } from 'codemirror';
import { autocompletion } from '@codemirror/autocomplete';

import { java } from '@codemirror/lang-java';
import { javascript } from '@codemirror/lang-javascript';
import { json } from '@codemirror/lang-json';
import { html } from '@codemirror/lang-html';
import { css } from '@codemirror/lang-css';
import { defaultKeymap } from '@codemirror/commands';
import { watch } from 'vue';
const emits = defineEmits(['update:value', 'change']);
const props = defineProps({
  value: {
    type: String,
  },
  language: {
    type: String,
    default: 'javascript',
  },
  beforeUpdate: {
    type: Function,
    default: (val) => val,
  },
});
const allKeyList = ref(['html', 'css', 'javascript']);
const localLanguage = ref('html');
const langConfigMap = {
  js: javascript(),
  java: java(),
  html: html(),
  css: css(),
  json: json(),
};
let editor = null;
let coder = ref();
// 获取当前编辑器中的内容字符串
const updateValue = useThrottleFn((value) => {
  console.log(value, '更新value');
  const newVal = props.beforeUpdate(value);
  emits('update:value', newVal);
  emits('change', newVal);
}, 500);
// 初始化编辑器
function initCodeContent() {
  localLanguage.value = props.language;
  if (!editor) {
    editor = new EditorView({
      doc: props.value ? props.value : 'Press Ctrl-Space in here...\n',
      extensions: [
        basicSetup,
        keymap.of([...defaultKeymap]),
        langConfigMap[props.language],
        oneDark,
        autocompletion({ override: [myCompletions] }),
        EditorView.updateListener.of((v) => {
          // 重复调用？？
          // console.log(v.state.doc.toString());
          updateValue(v.state.doc.toString());
        }),
      ],
      parent: coder.value,
      options: {
        lineNumbers: true,
        line: true,
        //ctrl-space唤起智能提示
        extraKeys: {
          Ctrl: 'autocomplete',
        },
        //括号匹配
        matchBrackets: true,
      },
    });
  }
  editor.dispatch({
    changes: {
      from: 0,
      to: editor.state.doc.length,
      insert: props.value ? props.value : 'Press Ctrl-Space in here...\n',
    },
  });
}

// 自定义的代码补全，options为自定义内容，以@开头进行匹配
function myCompletions(context) {
  let word = context.matchBefore(/@\w*/);
  if (!word && !context.explicit) return null;
  return {
    from: word.from ? word.from : context.pos,
    options: allKeyList.value,
  };
}
// 外部输入内容，添加到编辑器当前光标(或选中内容)所在的位置
// function insertCommandContant(insertContent) {
//   editor.dispatch({
//     changes: {
//       from: editor.state.selection.ranges[0].from,
//       to: editor.state.selection.ranges[0].to,
//       insert: insertContent,
//     },
//   });
// }
watch(
  () => props.value,
  (newValue, oldValue) => {
    if (editor) {
      const before = editor.state.selection.ranges[0];
      if (newValue !== oldValue) {
        editor.dispatch({
          changes: {
            from: 0,
            to: editor.state.doc.length,
            insert: newValue,
          },
          // 恢复光标位置 但是这样效率太低了
          selection: {
            anchor: before.anchor,
            head: before.head,
          },
        });
      }
    }
  },
  {
    immediate: true,
  }
);
onMounted(() => {
  initCodeContent();
});
</script>
<style>
html,
body {
  height: 100%;
}
#app {
  height: 100%;
}
.corder {
  height: 100%;
  position: relative;
}
.corder select {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
}
</style>
